#include "pcap-ethnet.h"
#include "appender.h"
#include <QDebug>

CPCapEthFrame::CPCapEthFrame(QObject *parent) :
    CPCapPacket(parent)
{

}

CPCapEthFrame::~CPCapEthFrame()
{

}

QString CPCapEthFrame::destMac() const
{
    return m_destMac;
}

void CPCapEthFrame::setDestMac(const QString &destMac)
{
    m_destMac = destMac;
    emit destMacChanged();
}

QString CPCapEthFrame::sourceMac() const
{
    return m_sourceMac;
}

void CPCapEthFrame::setSourceMac(const QString &sourceMac)
{
    m_sourceMac = sourceMac;
    emit sourceMacChanged();
}

QString CPCapEthFrame::type() const
{
    return m_type;
}

void CPCapEthFrame::setType(const QString &type)
{
    m_type = type;
    emit typeChanged();
}

int CPCapEthFrame::headerLength()
{
    return 14;
}

bool CPCapEthFrame::buildHeader(QByteArray &header)
{
    qDebug() << "Ethernet: build header";

    if (m_destMac.isEmpty()) {
        m_destMac = "00:00:00:00:00:01";
    }
    if (m_sourceMac.isEmpty()) {
        m_sourceMac = "00:00:00:00:00:02";
    }

    //THE DATA LINK HEADER
    CAppender apd(&header);
    //destination (6 bytes)
    QString destMac = m_destMac;
    destMac.replace(":", QString());
    if (destMac.length() != 12) {
        qCritical() << "Ethernet: invalid mac dst";
        return false;
    }
    if (!apd.appendHex(destMac)) {
        qCritical() << "Ethernet: append mac dst failed: " << m_destMac;
        return false;
    }
    //source (6 bytes)
    QString sourceMac = m_sourceMac;
    sourceMac.replace(":", QString());
    if (sourceMac.length() != 12) {
        qCritical() << "Ethernet: invalid mac src";
        return false;
    }
    if (!apd.appendHex(sourceMac)) {
        qCritical() << "Ethernet: append mac src failed: " << m_sourceMac;
        return false;
    }
    //type (2 bytes)
    if (!apd.appendUInt16(m_type)) {
        qCritical() << "Ethernet: append eth type failed: " << m_type;
        return false;
    }
    return true;
}

QString CPCapEthLLCFrame::dsap() const
{
    return m_dsap;
}

void CPCapEthLLCFrame::setDSAP(const QString &dsap)
{
    m_dsap = dsap;
    emit dsapChanged();
}

QString CPCapEthLLCFrame::ssap() const
{
    return m_ssap;
}

void CPCapEthLLCFrame::setSSAP(const QString &ssap)
{
    m_ssap = ssap;
    emit ssapChanged();
}

int CPCapEthLLCFrame::headerLength()
{
    return CPCapEthFrame::headerLength() + 3;
}

bool CPCapEthLLCFrame::buildHeader(QByteArray &header)
{
    if (!CPCapEthFrame::buildHeader(header)) {
        return false;
    }

    //THE 802.2 LOGICAL LINK CONTROL (LLC) HEADER
    CAppender apd(&header);
    //Destination Service Access Point (1 byte)
    if (!apd.appendUInt8(m_dsap)) {
        qCritical() << "Ethernet: append dsap failed: " << m_dsap;
        return false;
    }
    //Source Service Access Point (1 byte)
    if (!apd.appendUInt8(m_ssap)) {
        qCritical() << "Ethernet: append ssap failed: " << m_ssap;
        return false;
    }
    //Control Byte (1 byte)
    if (!apd.appendUInt8(m_ctrl)) {
        qCritical() << "Ethernet: append ctrl byte failed: " << m_ctrl;
        return false;
    }
    return true;
}

QString CPCapEthSNAPFrame::snap() const
{
    return m_snap;
}

void CPCapEthSNAPFrame::setSNAP(const QString &snap)
{
    m_snap = snap;
    emit snapChanged();
}

int CPCapEthSNAPFrame::headerLength()
{
    return CPCapEthLLCFrame::headerLength() + 5;
}

bool CPCapEthSNAPFrame::buildHeader(QByteArray &header)
{
    if (!CPCapEthLLCFrame::buildHeader(header)) {
        return false;
    }

    //THE SUB-NETWORK ACCESS PROTOCOL (SNAP) HEADER
    CAppender apd(&header);
    QString snap = m_snap;
    snap.replace(":", QString());
    if (snap.length() != 10) {
        return false;
    }
    if (!apd.appendHex(snap)) {
        qCritical() << "Ethernet: append snap failed: " << m_snap;
        return false;
    }
    return true;
}
